home *** CD-ROM | disk | FTP | other *** search
/ Programmer Power Tools / Programmer Power Tools.iso / editor / j414src.arc / C.C < prev    next >
C/C++ Source or Header  |  1989-10-10  |  18KB  |  770 lines

  1. /***************************************************************************
  2.  * This program is Copyright (C) 1986, 1987, 1988 by Jonathan Payne.  JOVE *
  3.  * is provided to you without charge, and with no warranty.  You may give  *
  4.  * away copies of JOVE, including sources, provided that this notice is    *
  5.  * included in all the files.                                              *
  6.  ***************************************************************************/
  7.  
  8. /* Contains commands for C mode.  Paren matching routines are in here. */
  9.  
  10. #include "jove.h"
  11. #include "re.h"
  12. #include "ctype.h"
  13. #include "disp.h"
  14.  
  15. private int
  16.     backslashed proto((char *, int));
  17. private void
  18. #if defined(CMT_FMT)
  19.     FillComment proto((char *format)),
  20. #endif
  21.     do_expr proto((int, int)),
  22.     FindMatch proto((int)),
  23.     parse_cmt_fmt proto((char *)),
  24.     strip_c proto((char *, char *));
  25.  
  26. extern void
  27.     FSexpr(),
  28.     FList(),
  29.     BSexpr(),
  30.     BList();
  31.  
  32. private int
  33. backslashed(lp, cpos)
  34. register char    *lp;
  35. register int    cpos;
  36. {
  37.     register int    cnt = 0;
  38.  
  39.     while (cpos > 0 && lp[--cpos] == '\\')
  40.         cnt += 1;
  41.     return (cnt % 2);
  42. }
  43.  
  44. private char    *p_types = "(){}[]";
  45. private int    mp_kind;
  46. #define MP_OKAY        0
  47. #define MP_MISMATCH    1
  48. #define MP_UNBALANCED    2
  49. #define MP_INCOMMENT    3
  50.  
  51. void
  52. mp_error()
  53. {
  54.     switch (mp_kind) {
  55.     case MP_MISMATCH:
  56.         message("[Mismatched parentheses]");
  57.         break;
  58.  
  59.     case MP_UNBALANCED:
  60.         message("[Unbalanced parenthesis]");
  61.         break;
  62.  
  63.     case MP_INCOMMENT:
  64.         message("[Inside a comment]");
  65.         break;
  66.  
  67.     case MP_OKAY:
  68.     default:
  69.         return;
  70.     }
  71.     rbell();
  72. }
  73.  
  74. /* Search from the current position for the paren that matches p_type.
  75.    Search in the direction dir.  If can_mismatch is YES then it is okay
  76.    to have mismatched parens.  If stop_early is YES then when an open
  77.    paren is found at the beginning of a line, it is assumed that there
  78.    is no point in backing up further.  This is so when you hit tab or
  79.    LineFeed outside, in-between procedure/function definitions, it won't
  80.    sit there searching all the way to the beginning of the file for a
  81.    match that doesn't exist.  {forward,backward}-s-expression are the
  82.    only ones that insist on getting the "true" story. */
  83.  
  84. Bufpos *
  85. m_paren(p_type, dir, can_mismatch, can_stop)
  86. int    p_type;
  87. register int    dir;
  88. int    can_mismatch;
  89. int    can_stop;
  90. {
  91.     static Bufpos    ret;
  92.     Bufpos    savedot,
  93.         *sp;
  94.     struct RE_block    re_blk;
  95.     int    count = 0;
  96.     register char    *lp,
  97.             c;
  98.     char    p_match,
  99.         re_str[128],
  100.         *cp,
  101.         quote_c = 0;
  102.     register int    c_char;
  103.     int    in_comment = -1,
  104.         stopped = NO;
  105.  
  106.     swritef(re_str, "[(){}[\\]%s]", (MajorMode(CMODE)) ? "/\"'" : "\"");
  107.     REcompile(re_str, 1, &re_blk);
  108.     if ((cp = strchr(p_types, p_type)) != NIL)
  109.         p_match = cp[dir];
  110.     else
  111.         complain("[Cannot match %c's]", p_type);
  112.     DOTsave(&savedot);
  113.  
  114.     /* To make things a little faster I avoid copying lines into
  115.        linebuf by setting curline and curchar by hand.  Warning:
  116.        this is slightly to very risky.  When I did this there were
  117.        lots of problems with procedures that expect the contents of
  118.        curline to be in linebuf. */
  119.     while (count >= 0) {
  120.         sp = docompiled(dir, &re_blk);
  121.         if (sp == 0)
  122.             break;
  123.         lp = lbptr(sp->p_line);
  124.  
  125.         curline = sp->p_line;
  126.         curchar = sp->p_char;    /* here's where I cheat */
  127.  
  128.         c_char = curchar;
  129.         if (dir == FORWARD)
  130.             c_char -= 1;
  131.         if (backslashed(lp, c_char))
  132.             continue;
  133.         c = lp[c_char];
  134.         /* check if this is a comment (if we're not inside quotes) */
  135.         if (quote_c == 0 && c == '/') {
  136.             int    new_ic = in_comment;
  137.  
  138.             /* close comment */
  139.             if ((c_char != 0) && lp[c_char - 1] == '*') {
  140.                 new_ic = (dir == FORWARD) ? NO : YES;
  141.                 if (new_ic == NO && in_comment == -1) {
  142.                     count = 0;
  143.                     quote_c = 0;
  144.                 }
  145.             } else if (lp[c_char + 1] == '*') {
  146.                 new_ic = (dir == FORWARD) ? YES : NO;
  147.                 if (new_ic == NO && in_comment == -1) {
  148.                     count = 0;
  149.                     quote_c = 0;
  150.                 }
  151.             }
  152.             in_comment = new_ic;
  153.         }
  154.         if (in_comment == YES)
  155.             continue;
  156.         if (c == '"' || c == '\'') {
  157.             if (quote_c == c)
  158.                 quote_c = 0;
  159.             else if (quote_c == 0)
  160.                 quote_c = c;
  161.         }
  162.         if (quote_c != 0)
  163.             continue;
  164.         if (isopenp(c)) {
  165.             count += dir;
  166.             if (c_char == 0 && can_stop == YES && count >= 0) {
  167.                 stopped = YES;
  168.                 break;
  169.             }
  170.         } else if (isclosep(c))
  171.             count -= dir;
  172.     }
  173.  
  174.     ret.p_line = curline;
  175.     ret.p_char = curchar;
  176.  
  177.     curline = savedot.p_line;
  178.     curchar = savedot.p_char;    /* here's where I undo it */
  179.  
  180.     if (count >= 0)
  181.         mp_kind = MP_UNBALANCED;
  182.     else if (c != p_match)
  183.         mp_kind = MP_MISMATCH;
  184.     else
  185.         mp_kind = MP_OKAY;
  186.  
  187.     /* If we stopped (which means we were allowed to stop) and there
  188.        was an error, we clear the error so no error message is printed.
  189.        An error should be printed ONLY when we are sure about the fact,
  190.        namely we didn't stop prematurely HOPING that it was the right
  191.        answer. */
  192.     if (stopped && mp_kind != MP_OKAY) {
  193.         mp_kind = MP_OKAY;
  194.         return 0;
  195.     }
  196.     if (mp_kind == MP_OKAY || (mp_kind == MP_MISMATCH && can_mismatch == YES))
  197.         return &ret;
  198.     return 0;
  199. }
  200.  
  201. private void
  202. do_expr(dir, skip_words)
  203. register int    dir;
  204. int    skip_words;
  205. {
  206.     register char    c,
  207.             syntax = (dir == FORWARD) ? _Op : _Cl;
  208.  
  209.     if (dir == BACKWARD)
  210.         b_char(1);
  211.     c = linebuf[curchar];
  212.     for (;;) {
  213.         if (!skip_words && ismword(c)) {
  214.             WITH_TABLE(curbuf->b_major)
  215.             if (dir == FORWARD)
  216.             f_word(1);
  217.             else
  218.             b_word(1);
  219.             END_TABLE();
  220.             break;
  221.         } else if (has_syntax(c, syntax)) {
  222.             FindMatch(dir);
  223.             break;
  224.         }
  225.         f_char(dir);
  226.         if (eobp() || bobp())
  227.             return;
  228.         c = linebuf[curchar];
  229.     }
  230. }
  231.  
  232. void
  233. FSexpr()
  234. {
  235.     register int    num = arg_value();
  236.  
  237.     if (num < 0) {
  238.         set_arg_value(-num);
  239.         BSexpr();
  240.     }
  241.     while (--num >= 0)
  242.         do_expr(FORWARD, NO);
  243. }
  244.  
  245. void
  246. FList()
  247. {
  248.     register int    num = arg_value();
  249.  
  250.     if (num < 0) {
  251.         set_arg_value(-num);
  252.         BList();
  253.     }
  254.     while (--num >= 0)
  255.         do_expr(FORWARD, YES);
  256. }
  257.  
  258. void
  259. BSexpr()
  260. {
  261.     register int    num = arg_value();
  262.  
  263.     if (num < 0) {
  264.         negate_arg_value();
  265.         FSexpr();
  266.     }
  267.     while (--num >= 0)
  268.         do_expr(BACKWARD, NO);
  269. }
  270.  
  271. void
  272. BList()
  273. {
  274.     register int    num = arg_value();
  275.  
  276.     if (num < 0) {
  277.         negate_arg_value();
  278.         FList();
  279.     }
  280.     while (--num >= 0)
  281.         do_expr(BACKWARD, YES);
  282. }
  283.  
  284. void
  285. BUpList()
  286. {
  287.     Bufpos    *mp;
  288.     char    c = (MajorMode(CMODE) ? '}' : ')');
  289.  
  290.     mp = m_paren(c, BACKWARD, NO, YES);
  291.     if (mp == 0)
  292.         mp_error();
  293.     else
  294.         SetDot(mp);
  295. }
  296.  
  297. void
  298. FDownList()
  299. {
  300.     Bufpos    *sp;
  301.     char    *sstr = (MajorMode(CMODE) ? "[{([\\])}]" : "[()]"),
  302.         *lp;
  303.  
  304.     sp = dosearch(sstr, FORWARD, YES);
  305.     if (sp != 0)
  306.         lp = lcontents(sp->p_line);
  307.     if (sp == 0 || has_syntax(lp[sp->p_char - 1], _Cl))
  308.         complain("[No contained expression]");
  309.     SetDot(sp);
  310. }
  311.  
  312. /* Move to the matching brace or paren depending on the current position
  313.    in the buffer. */
  314.  
  315. private void
  316. FindMatch(dir)
  317. int    dir;
  318. {
  319.     register Bufpos    *bp;
  320.     register char    c = linebuf[curchar];
  321.  
  322.     if ((strchr(p_types, c) == 0) ||
  323.         (backslashed(linebuf, curchar)))
  324.         complain((char *) 0);
  325.     if (dir == FORWARD)
  326.         f_char(1);
  327.     bp = m_paren(c, dir, YES, NO);
  328.     if (dir == FORWARD)
  329.         b_char(1);
  330.     if (bp != 0)
  331.         SetDot(bp);
  332.     mp_error();    /* if there is an error the user wants to
  333.                know about it */
  334. }
  335.  
  336. #define ALIGN_ARGS    (-1)
  337.  
  338. /* If CArgIndent == ALIGN_ARGS then the indentation routine will
  339.    indent a continued line by lining it up with the first argument.
  340.    Otherwise, it will indent CArgIndent characters past the indent
  341.    of the first line of the procedure call. */
  342.  
  343. int    CArgIndent = ALIGN_ARGS;
  344.  
  345. /* indent for C code */
  346. Bufpos *
  347. c_indent(brace)
  348. int    brace;
  349. {
  350.     Bufpos    *bp;
  351.     int    new_indent = 0,
  352.         current_indent,
  353.         increment;
  354.  
  355.     if (brace == NO)
  356.         increment = CIndIncrmt;
  357.     else
  358.         increment = 0;
  359.     /* Find matching paren, which may be a mismatch now.  If it
  360.        is not a matching curly brace then it is a paren (most likely).
  361.        In that case we try to line up the arguments to a procedure
  362.        or inside an of statement. */
  363.     if ((bp = m_paren('}', BACKWARD, YES, YES)) != NIL) {
  364.         Bufpos    save;
  365.         int    matching_indent;
  366.  
  367.         DOTsave(&save);
  368.         SetDot(bp);        /* go to matching paren */
  369.         ToIndent();
  370.         matching_indent = calc_pos(linebuf, curchar);
  371.         SetDot(bp);
  372.         switch (linebuf[curchar]) {
  373.         case '{':
  374.             new_indent = matching_indent;
  375.             if (!bolp()) {
  376.                 b_char(1);
  377.                 /* If we're not within the indent then we
  378.                    can assume that there is either a C keyword
  379.                    line DO on the line before the brace, or
  380.                    there is a parenthesized expression.  If
  381.                    that's the case we want to go backward
  382.                    over that to the beginning of the expression
  383.                    so that we can get the correct indent for
  384.                    this matching brace.  This handles wrapped
  385.                    if statements, etc. */
  386.                 if (!within_indent()) {
  387.                     Bufpos    savematch;
  388.  
  389.                     savematch = *bp;
  390.  
  391.                     do_expr(BACKWARD, NO);
  392.                     ToIndent();
  393.                     new_indent = calc_pos(linebuf, curchar);
  394.  
  395.                     /* do_expr() calls b_paren, which
  396.                        returns a pointer to a structure,
  397.                        and that pointer is in BP so we
  398.                        have to save away the matching
  399.                        paren and restore it in the
  400.                        following line ... sigh */
  401.                     *bp = savematch;
  402.                 }
  403.             }
  404.             if (brace == NO)
  405.                 new_indent += (increment - (new_indent % increment));
  406.             break;
  407.             
  408.         case '(':
  409.             if (CArgIndent == ALIGN_ARGS) {
  410.                 f_char(1);
  411.                 new_indent = calc_pos(linebuf, curchar);
  412.             } else
  413.                 new_indent = matching_indent + CArgIndent;
  414.             break;
  415.         }
  416.         SetDot(&save);
  417.     }
  418.  
  419.     /* new_indent is the "correct" place to indent.  Now we check to
  420.        see if what we consider as the correct place to indent is to
  421.        the LEFT of where we already are.  If it is, and we are NOT
  422.        handling a brace, then we assume that the person wants to tab
  423.        in further than what we think is right (for some reason) and
  424.        so we allow that. */
  425.  
  426.     ToIndent();
  427.     current_indent = calc_pos(linebuf, curchar);
  428.     if (brace == NO && new_indent <= current_indent)
  429.         new_indent = current_indent + (increment - (current_indent % increment));
  430.     Bol();
  431.     DelWtSpace();            /* nice uniform Tabs*Space* */
  432.     n_indent(new_indent);
  433.  
  434.     return bp;
  435. }
  436.  
  437. static void
  438. re_indent(incr)
  439. int    incr;
  440. {
  441.     Line    *l1, *l2, *lp;
  442.     int    c1, c2;
  443.     Mark    *m = CurMark();
  444.     Bufpos    savedot;
  445.  
  446.     DOTsave(&savedot);
  447.     l1 = curline;
  448.     c1 = curchar;
  449.     l2 = m->m_line;
  450.     c2 = m->m_char;
  451.     (void) fixorder(&l1, &c1, &l2, &c2);
  452.     for (lp = l1; lp != l2->l_next; lp = lp->l_next) {
  453.         int    indent;
  454.  
  455.         SetLine(lp);
  456.         ToIndent();
  457.         indent = calc_pos(linebuf, curchar);
  458.         if (indent != 0 || linebuf[0] != '\0')
  459.             n_indent(indent + incr);
  460.     }
  461.     SetDot(&savedot);
  462. }
  463.  
  464. void
  465. LRShift()
  466. {
  467.     int    amnt;
  468.  
  469.     if (is_an_arg())
  470.         amnt = arg_value();
  471.     else
  472.         amnt = CIndIncrmt;
  473.     re_indent(-amnt);
  474. }
  475.  
  476. void
  477. RRShift()
  478. {
  479.     int    amnt;
  480.  
  481.     if (is_an_arg())
  482.         amnt = arg_value();
  483.     else
  484.         amnt = CIndIncrmt;
  485.     re_indent(amnt);
  486. }
  487.  
  488. #if defined(CMT_FMT)
  489.  
  490. char    CmtFmt[80] = "/*%n%! * %c%!%n */";
  491.  
  492. void
  493. Comment()
  494. {
  495.     FillComment(CmtFmt);
  496. }
  497.  
  498. /* Strip leading and trailing white space.  Skip over any imbedded '\r's. */
  499.  
  500. private void
  501. strip_c(from, to)
  502. char    *from,
  503.     *to;
  504. {
  505.     register char    *fr_p = from,
  506.             *to_p = to,
  507.             c;
  508.  
  509.     while ((c = *fr_p) != '\0') {
  510.         if (c == ' ' || c == '\t' || c == '\r')
  511.             fr_p += 1;
  512.         else
  513.             break;
  514.     }
  515.     while ((c = *fr_p) != '\0') {
  516.         if (c != '\r')
  517.             *to_p++ = c;
  518.         fr_p += 1;
  519.     }
  520.     while (--to_p >= to)
  521.         if (*to_p != ' ' && *to_p != '\t')
  522.             break;
  523.     *++to_p = '\0';
  524. }
  525.  
  526. private char    open_c[20],    /* the open comment format string */
  527.         open_pat[20],    /* the search pattern for open comment */
  528.         l_header[20],    /* the prefix for each comment line */
  529.         l_trailer[20],    /* the suffix ... */
  530.         close_c[20],
  531.         close_pat[20];
  532.  
  533. private char    *const comment_body[] = {
  534.     open_c,
  535.     l_header,
  536.     l_trailer,
  537.     close_c
  538. };
  539.  
  540. private int    nlflags;
  541.  
  542. /* Fill in the data structures above from the format string.  Don't return
  543.    if there's trouble. */
  544.  
  545. private void
  546. parse_cmt_fmt(str)
  547. char    *str;
  548. {
  549.     register char    *fmtp = str;
  550.     register char    *const *c_body = comment_body,
  551.             *body_p = *c_body;
  552.     int    c,
  553.         newlines = 1;
  554.  
  555.     /* pick apart the comment string */
  556.     while ((c = *fmtp++) != '\0') {
  557.         if (c != '%') {
  558.             *body_p++ = c;
  559.             continue;
  560.         }
  561.         switch(c = *fmtp++) {
  562.         case 'n':
  563.             if (newlines == 2 || newlines == 3)
  564.                 complain("%n not allowed in line header or trailer: %s",
  565.                   fmtp - 2);
  566.             nlflags += newlines;
  567.             *body_p++ = '\r';
  568.             break;
  569.         case 't':
  570.             *body_p++ = '\t';
  571.             break;
  572.         case '%':
  573.             *body_p++ = '%';
  574.             break;
  575.         case '!':
  576.         case 'c':
  577.             newlines += 1;
  578.             *body_p++ = '\0';
  579.             body_p = *++c_body;
  580.             break;
  581.         default:
  582.             complain("[Unknown comment escape: %%%c]", c);
  583.             break;
  584.         }
  585.     }
  586.     *body_p = '\0';
  587.     /* make search patterns */
  588.     strip_c(open_c, open_pat);
  589.     strip_c(close_c, close_pat);
  590. }
  591.  
  592. #define NL_IN_OPEN_C  ((nlflags % 4) == 1)
  593. #define NL_IN_CLOSE_C (nlflags >= 4)
  594.  
  595. private void
  596. FillComment(format)
  597. char    *format;
  598. {
  599.     int    saveRMargin,
  600.         indent_pos,
  601.         close_at_dot = NO;
  602.     size_t    header_len,
  603.         trailer_len;
  604.     register char    *cp;
  605.     static char    inside_err[] = "[Must be between %s and %s to re-format]";
  606.     Bufpos    open_c_pt,
  607.         close_c_pt,
  608.         tmp_bp,
  609.         *match_o,
  610.         *match_c;
  611.     Mark    *entry_mark,
  612.         *open_c_mark,
  613.         *savedot;
  614.  
  615.     parse_cmt_fmt(format);
  616.     /* figure out if we're "inside" a comment */
  617.     if ((match_o = dosearch(open_pat, BACKWARD, 0)) == 0)
  618.         complain("No opening %s to match to.", open_pat);
  619.     open_c_pt = *match_o;
  620.     if ((match_c = dosearch(close_pat, BACKWARD, NO)) != 0 &&
  621.         inorder(open_c_pt.p_line, open_c_pt.p_char,
  622.             match_c->p_line, match_c->p_char))
  623.         complain(inside_err, open_pat, close_pat);
  624.     if ((match_o = dosearch(open_pat, FORWARD, NO)) != 0) {
  625.         tmp_bp = *match_o;
  626.         match_o = &tmp_bp;
  627.     }
  628.     if ((match_c = dosearch(close_pat, FORWARD, 0)) != (Bufpos *) 0)
  629.         close_c_pt = *match_c;
  630.  
  631.     /* Here's where we figure out whether to format from dot or from
  632.        the close comment.  Note that we've already searched backwards to
  633.        find the open comment symbol for the comment we are formatting.
  634.        The open symbol mentioned below refers to the possible existence
  635.        of the next comment.  There are 5 cases:
  636.         1) no open or close symbol        ==> dot
  637.         2) open, but no close symbol        ==> dot
  638.         3) close, but no open            ==> close
  639.         4) open, close are inorder        ==> dot
  640.         5) open, close are not inorder        ==> close */
  641.  
  642.  
  643.     if (match_o == (Bufpos *) 0) {
  644.         if (match_c == (Bufpos *) 0)
  645.             close_at_dot = YES;
  646.     } else if (match_c == (Bufpos *) 0)
  647.         close_at_dot = YES;
  648.     else if (inorder(match_o->p_line, match_o->p_char,
  649.          match_c->p_line, match_c->p_char))
  650.         close_at_dot = YES;
  651.     if (close_at_dot) {
  652.         close_c_pt.p_line = curline;
  653.         close_c_pt.p_char = curchar;
  654.     } else {
  655.         SetDot(match_c);
  656.     }
  657.     SetDot(&open_c_pt);
  658.     open_c_mark = MakeMark(curline, curchar, M_FLOATER);
  659.     indent_pos = calc_pos(linebuf, curchar);
  660.     /* search for a close comment; delete it if it exits */
  661.     SetDot(&close_c_pt);
  662.     if (close_at_dot == 0)
  663.         del_char(BACKWARD, (int)strlen(close_pat), NO);
  664.     entry_mark = MakeMark(curline, curchar, M_FLOATER);
  665.     ToMark(open_c_mark);
  666.     /* always separate the comment body from anything preceeding it */
  667.     LineInsert(1);
  668.     DelWtSpace();
  669.     Bol();
  670.     for (cp = open_c; *cp; cp++) {
  671.         if (*cp == '\r') {
  672.             if (!eolp())
  673.                 LineInsert(1);
  674.             else
  675.                 line_move(FORWARD, 1, NO);
  676.         } else if (*cp == ' ' || *cp == '\t') {
  677.             if (linebuf[curchar] != *cp)
  678.                 insert_c(*cp, 1);
  679.         } else
  680.             /* Since we matched the open comment string on this
  681.                line, we don't need to worry about crossing line
  682.                boundaries. */
  683.             curchar += 1;
  684.     }
  685.     savedot = MakeMark(curline, curchar, M_FLOATER);
  686.  
  687.     /* We need to strip the line header pattern of leading white space
  688.        since we need to match the line after all of its leading
  689.        whitespace is gone. */
  690.     for (cp = l_header; *cp && (isspace(*cp)); cp++)
  691.         ;
  692.     header_len = strlen(cp);
  693.     trailer_len = strlen(l_trailer);
  694.  
  695.     /* Strip each comment line of the open and close comment strings
  696.        before reformatting it. */
  697.  
  698.     do {
  699.         Bol();
  700.         DelWtSpace();
  701.         if (header_len && strncmp(linebuf, cp, header_len)==0)
  702.             del_char(FORWARD, (int)header_len, NO);
  703.         if (trailer_len) {
  704.             Eol();
  705.             if (((size_t)curchar > trailer_len) &&
  706.                 (strncmp(&linebuf[curchar - trailer_len],
  707.                       l_trailer, trailer_len)==0))
  708.                 del_char(BACKWARD, (int)trailer_len, NO);
  709.         }
  710.         if (curline->l_next != 0)
  711.             line_move(FORWARD, 1, NO);
  712.         else
  713.             break;
  714.     } while (curline != entry_mark->m_line->l_next);
  715.  
  716.     do_set_mark(savedot->m_line, savedot->m_char);
  717.     ToMark(entry_mark);
  718.     saveRMargin = RMargin;
  719.     RMargin = saveRMargin - strlen(l_header) -
  720.           strlen(l_trailer) - indent_pos + 2;
  721.     do_rfill(NO);
  722.     RMargin = saveRMargin;
  723.     /* get back to the start of the comment */
  724.     PopMark();
  725.     do {
  726.         if (curline == open_c_mark->m_line->l_next) {
  727.             ;
  728.         } else {
  729.             Bol();
  730.             n_indent(indent_pos);
  731.             ins_str(l_header, NO);
  732.         }
  733.         Eol();
  734.         if (!NL_IN_CLOSE_C && (curline == entry_mark->m_line))
  735.             ;
  736.         else
  737.             ins_str(l_trailer, NO);
  738.         if (curline->l_next != 0)
  739.             line_move(FORWARD, 1, NO);
  740.         else
  741.             break;
  742.     } while (curline != entry_mark->m_line->l_next);
  743.     /* handle the close comment symbol */
  744.     if (curline == entry_mark->m_line->l_next) {
  745.         line_move(BACKWARD, 1, NO);
  746.         Eol();
  747.     }
  748.     DelWtSpace();
  749.     /* if the addition of the close symbol would cause the line to be
  750.        too long, put the close symbol on the next line. */
  751.     if (!(NL_IN_CLOSE_C) &&
  752.       (int)strlen(close_c) + calc_pos(linebuf, curchar) > RMargin) {
  753.         LineInsert(1);
  754.         n_indent(indent_pos);
  755.     }
  756.     for (cp = close_c; *cp; cp++) {
  757.         if (*cp == '\r') {
  758.             LineInsert(1);
  759.             n_indent(indent_pos);
  760.         } else
  761.             insert_c(*cp, 1);
  762.     }
  763.     ToMark(open_c_mark);
  764.     Eol();
  765.     del_char(FORWARD, 1, NO);
  766. }
  767.  
  768. #endif /* CMT_FMT */
  769.  
  770.